#include "peer_connection.h"
#include "ice/ice_credentials.h"

#include <rtc_base/logging.h>
#include <absl/algorithm/container.h>

namespace xrtc {

static RtpDirection getDirection(bool send, bool recv) {
    if (send && recv) {
        return RtpDirection::k_send_recv;
    } else if (send && !recv) {
        return RtpDirection::k_send_only;
    } else if (!send && recv) {
        return RtpDirection::k_recv_only;
    } else {
        return RtpDirection::k_inactive;
    }
}

int PeerConnection::init(rtc::RTCCertificate *certificate) {
    m_certificate = certificate;
    return 0;
}

// 由用户参数的参数来设置对应的属性值
std::string PeerConnection::createOffer(const RTCOfferAnswerOptions& options) {
    if (options.dtls_on && !m_certificate) {
        RTC_LOG(LS_WARNING) << "certificate is null";
        return "";
    }

    m_local_description = std::make_unique<SessionDescription>(SdpType::k_offer);
    IceParameters ice_parameters = IceCredentials::createRandomIceCredentials();

    // 如果用户接受音频流
    if (options.recv_audio) {
        auto audio = std::make_shared<AudioContentDescription>();
        audio->setDirection(getDirection(options.send_audio, options.recv_audio));
        audio->setRtcpMux(options.use_rtcp_mux);
        m_local_description->addContent(audio);
        m_local_description->addTransportInfo(audio->mid(), ice_parameters, m_certificate);
    }

    // 如果用户接受视频流
    if (options.recv_video) {
        auto video = std::make_shared<VideoContentDescription>();
        video->setDirection(getDirection(options.send_video, options.recv_video));
        video->setRtcpMux(options.use_rtcp_mux);
        m_local_description->addContent(video);
        m_local_description->addTransportInfo(video->mid(), ice_parameters, m_certificate);
    }

    // 采用BUNDLE方式
    if (options.use_rtp_mux) {
        ContentGroup offer_bundler("BUNDLE");
        for (auto content : m_local_description->getContents()) {
            offer_bundler.addContentName(content->mid());
        }

        if (!offer_bundler.getContentNames().empty()) {
            m_local_description->addGroup(offer_bundler);
        }
    }

    // 设置sdp
    m_transport_controller->set_local_description(m_local_description.get());

    return m_local_description->toString();
}


// 最终处理ICE Candidate收集完成后的回调函数
void PeerConnection::on_candidate_allocate_done(TransportController* /* transport_controller */,
        const std::string& transport_name,
        IceCandidateComponent /* component */,
        const std::vector<Candidate>& candidates) {
    for (const auto &c : candidates) {
        RTC_LOG(LS_INFO) << "candidate gathered, transport_name: " << transport_name << ", " << c.to_string();
    }

    if (!m_local_description) {
        return;
    }

    std::shared_ptr<MediaContentDescription> content = m_local_description->get_content(transport_name);
    if (content) {
        content->add_candidates(candidates);
    }
    
}        

static std::string get_attribute(const std::string& line,
        bool is_rn)
{
    std::vector<std::string> fields;
    size_t size = rtc::tokenize(line, ':', &fields);
    if (size != 2) {
        RTC_LOG(LS_WARNING) << "get attribute error: " << line;
        return "";
    }

    if (is_rn) {
        return fields[1].substr(0, fields[1].length() - 1);
    }

    return fields[1];
}

static int parse_transport_info(TransportDescription* td,
        const std::string& line,
        bool is_rn)
{
    if (line.find("a=ice-ufrag") != std::string::npos) {
        td->m_ICE_ufrag = get_attribute(line, is_rn);
        if (td->m_ICE_ufrag.empty()) {
            return -1;
        }
    } else if (line.find("a=ice-pwd") != std::string::npos) {
        td->m_ICE_pwd = get_attribute(line, is_rn);
        if (td->m_ICE_pwd.empty()) {
            return -1;
        }
    } else if (line.find("a=fingerprint") != std::string::npos) {
        std::vector<std::string> items;
        rtc::tokenize(line, ' ', &items);
        if (items.size() != 2) {
            RTC_LOG(LS_WARNING) << "parse a=fingerprint error: " << line;
            return -1;
        }

        // a=fingerprint: 14
        std::string alg = items[0].substr(14);
        absl::c_transform(alg, alg.begin(), ::tolower);
        std::string content = items[1];
        if (is_rn) {
            content = content.substr(0, content.length() - 1);
        }
        
        td->m_identity_fingerprint = rtc::SSLFingerprint::CreateUniqueFromRfc4572(
                alg, content);
        if (!(td->m_identity_fingerprint.get())) {
            RTC_LOG(LS_WARNING) << "create fingerprint error: " << line;
            return -1;
        }
    }

    return 0;
}

// 设置远端的SDP
int PeerConnection::set_remote_sdp(const std::string& sdp) {
    std::vector<std::string> fields;
    size_t size = rtc::tokenize(sdp, '\n', &fields);
    if (size <= 0) {
        RTC_LOG(LS_WARNING) << "sdp invalid";
        return -1;
    }
    
    bool is_rn = false;
    if (sdp.find("\r\n") != std::string::npos) {
        is_rn = true;
    }
    
    m_remote_description = std::make_unique<SessionDescription>(SdpType::k_answer);

    std::string media_type;
    
    auto audio_td = std::make_shared<TransportDescription>();
    auto video_td = std::make_shared<TransportDescription>();

    auto audio_content = std::make_shared<AudioContentDescription>();
    auto video_content = std::make_shared<VideoContentDescription>();

    for (auto field : fields) {
        if (field.find("a=group:BUNDLE") != std::string::npos) {
            std::vector<std::string> items;
            if (is_rn) {
                field = field.substr(0, field.length() - 1);
            }
            rtc::split(field, ' ', &items);
            if (items.size() > 1) {
                ContentGroup answer_bundle("BUNDLE");
                for (size_t i = 1; i < items.size(); ++i) {
                    answer_bundle.addContentName(items[i]);
                }
                m_remote_description->addGroup(answer_bundle);
            }
        } else if (field.find("m=") != std::string::npos) {
            std::vector<std::string> items;
            rtc::split(field, ' ', &items);
            if (items.size() <= 2) {
                RTC_LOG(LS_WARNING) << "parse m= error: " << field;
                return -1;
            }

            // m=audio/video
            media_type = items[0].substr(2);
            if ("audio" == media_type) {
                m_remote_description->addContent(audio_content);
                audio_td->m_mid = "audio";
            } else if ("video" == media_type){
                m_remote_description->addContent(video_content);
                video_td->m_mid = "video";
            }
        }

        if ("audio" == media_type) {
            if (parse_transport_info(audio_td.get(), field, is_rn) != 0) {
                return -1;
            }

        } else if ("video" == media_type) {
            if (parse_transport_info(video_td.get(), field, is_rn) != 0) {
                return -1;
            }
        }
    }
    
    m_remote_description->add_transport_info(audio_td);
    m_remote_description->add_transport_info(video_td);

    m_transport_controller->set_remote_description(m_remote_description.get());

    return 0;
}

} // namespace xrtc